import json
import time

import cv2
import numpy
import win32api
import win32con
import win32gui
import win32print
import win32ui


class Window:
    def __init__(self, name, cls=None):
        hDesktopDC = win32gui.GetDC(0)
        self.scale = win32print.GetDeviceCaps(hDesktopDC, win32con.DESKTOPHORZRES) \
            / win32print.GetDeviceCaps(hDesktopDC, win32con.HORZRES)
        win32gui.ReleaseDC(None, hDesktopDC)

        self.hWnd = win32gui.FindWindow(cls, name)
        assert self.hWnd
        self.hWndDC = win32gui.GetDC(self.hWnd)
        self.hMfcDc = win32ui.CreateDCFromHandle(self.hWndDC)
        self.hMemDc = self.hMfcDc.CreateCompatibleDC()

    def capture(self):
        width, height = [round(i*self.scale)
                         for i in win32gui.GetClientRect(self.hWnd)[2:]]
        hBmp = win32ui.CreateBitmap()
        hBmp.CreateCompatibleBitmap(self.hMfcDc, width, height)
        self.hMemDc.SelectObject(hBmp)
        self.hMemDc.BitBlt((0, 0), (width, height),
                           self.hMfcDc, (0, 0), win32con.SRCCOPY)
        result = numpy.frombuffer(hBmp.GetBitmapBits(
            True), dtype='uint8').reshape(height, width, 4)[..., :3]
        win32gui.DeleteObject(hBmp.GetHandle())
        return result

    def click(self, hold=0):
        win32api.PostMessage(self.hWnd, win32con.WM_LBUTTONDOWN, 0, 0)
        time.sleep(hold)
        win32api.PostMessage(self.hWnd, win32con.WM_LBUTTONUP, 0, 0)

    def __del__(self):
        self.hMemDc.DeleteDC()
        self.hMfcDc.DeleteDC()
        win32gui.ReleaseDC(self.hWnd, self.hWndDC)


window = Window('原神')


READY = cv2.imread('image/ready.png')
READYMASK = cv2.imread('image/readymask.png')
FRONT = cv2.imread('image/front.png')
FRONTMASK = cv2.imread('image/frontmask.png')
BACK = cv2.imread('image/back.png')
BACKMASK = cv2.imread('image/backmask.png')
CUR = cv2.imread('image/cur.png')
CURMASK = cv2.imread('image/curmask.png')


class Check:
    def __init__(self, im=None):
        self.im = cv2.resize(window.capture() if im is None else im, (1280, 720))

    def isReady(self):
        return .05 > cv2.minMaxLoc(cv2.matchTemplate(self.im[130:155, 588:685], READY, cv2.TM_SQDIFF_NORMED, mask=READYMASK))[0]

    def getPos(self):
        loc = cv2.minMaxLoc(cv2.matchTemplate(
            self.im[57:96, 470:810], CUR, cv2.TM_SQDIFF_NORMED, mask=CURMASK))
        if loc[0] > .05:
            return None
        return (
            cv2.minMaxLoc(cv2.matchTemplate(
                self.im[57:96, 470:810], FRONT, cv2.TM_SQDIFF_NORMED, mask=FRONTMASK))[2][0],
            cv2.minMaxLoc(cv2.matchTemplate(
                self.im[57:96, 470:810], BACK, cv2.TM_SQDIFF_NORMED, mask=BACKMASK))[2][0],
            loc[2][0]
        )


with open('config.json') as f:
    config = json.load(f)

if __name__ == '__main__':
    print('initialized')

    while True:
        if config['startKey']:
            while win32api.GetKeyState(config['startKey']) >= 0:
                time.sleep(.05)
        print('wait')
        while not Check().isReady():
            time.sleep(.05)
        print('ready')
        window.click(1)
        print('go')
        while True:
            pos = Check().getPos()
            if pos is None:
                break
            front, back, cur = pos
            buf = ['[']+[' ']*34+[']']
            buf[front//10+2] = '<'
            buf[back//10+2] = '>'
            buf[cur//10+2] = '|'
            print(''.join(buf), end='\r')
            if cur + 5 < (back + front) // 2:
                window.click(.1)
        print(' '*36, end='\r')
        print('next')
